﻿#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <algorithm>
using namespace std;

// 实现一个不能被继承的类
#if 0
// c++98 方法是把构造函数放在私有中，这样就不可以继承了
// 但是继承不会直接报错，只有访问后会报错
class Parents
{
public:
	void Print()
	{
		cout << "Parents::_num:" << _num << endl;
	}
protected:
	int _num = 1;
private:
	Parents(int num = 1)
		:_num(num)
	{}
};

// c++11 新增了⼀个final关键字，final修改⽗类，⼦类就不能继承了。
class Parents final
{
public:
	void Print()
	{
		cout << "Parents::_num:" << _num << endl;
	}
protected:
	int _num = 1;
private:
	Parents(int num = 1)
		:_num(num)
	{}
};

class Child : public Parents
{
public:
protected:
	int _id = 1;
};

int main()
{
	Child d;
	return 0;
}


// 友元关系不可以继承
class B;
class A
{
public:
	friend void Display(const A& p, const B& s);
protected:
	string _name; // 姓名
};

class B : public A
{
protected :
	int _stuNum; // 学号
};

void Display(const A& p, const B& s)
{
	cout << p._name << endl;
	cout << s._stuNum << endl; // err
}

int main()
{
	return 0;
}

// 继承和静态成员
// 无论基类派生出多少个派生类，或者说是无论父类派生多少子类，静态成员有且只有一个
class Person
{
public :
	string _name;
	static int _count;
};

// 静态成员变量需要在类外初始化
int Person::_count = 0;

class Student : public Person
{
	protected :
	int _stuNum;
};

int main()
{
	Student s;
	Student s1;
	Person p;
	s._count++;
	s1._count++;

	cout << Person::_count << endl;

	// 这⾥的运⾏结果可以看到⾮静态成员_name的地址是不⼀样的
	// 说明⼦类继承下来了，⽗⼦类对象各有⼀份
	cout << &p._name << endl;
	cout << &s._name << endl;
	// 这⾥的运⾏结果可以看到静态成员_count的地址是⼀样的
	// 说明⼦类和⽗类共⽤同⼀份静态成员
	cout << &p._count << endl;
	cout << &s._count << endl;
	// 公有的情况下，⽗⼦类指定类域都可以访问静态成员
	cout << Person::_count << endl;
	cout << Student::_count << endl;
}


// 多继承和菱形继承 - 我们要避免菱形继承
// 棱形继承存在数据冗余和二义性
class Person
{
public :
	string _name; // 姓名
};

class Student : public Person
{
protected:
	int _num; //学号
};

class Teacher : public Person
{
protected :
	int _id; // 职⼯编号
};

class Assistant : public Student, public Teacher
{
protected :
	string _majorCourse; // 主修课程
};

int main()
{
	// 编译报错：error C2385: 对“_name”的访问不明确
	Assistant a;
	//a._name = "peter";
	// 需要显⽰指定访问哪个⽗类的成员可以解决⼆义性问题，但是数据冗余问题⽆法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";
	return 0;
}

// 冗余和二义性还可以通过虚继承解决 使用virtual
class Person
{
public:
	string _name; // 姓名
};

class Student : virtual public Person
{
protected:
	int _num; //学号
};

class Teacher : virtual public Person
{
protected:
	int _id; // 职⼯编号
};

class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

int main()
{
	Assistant a;
	a._name = "peter";

	return 0;
}

// 多继承中的指针偏移问题
class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base2, public Base1 { public: int _d; };
int main()
{
	Derive d;
	Base1* p1 = &d;
	Base2* p2 = &d;
	Derive* p3 = &d;
	//A：p1==p2==p3 B：p1<p2<p3 C：p1==p3!=p2 D：p1!=p2!=p3 E: p2==p3!=p1
	// 首先p3毫无疑问指向对象d的起始位置,先继承的Base2，
	// 后继承Base1，所以指向Base1的指针要偏移Base2的大小
	// 选择E
	cout << p1 << endl;
	cout << p2 << endl;
	cout << p3 << endl;
	return 0;
}
#endif

// 继承和组合 
// public继承是is-a的关系,每个子类对象都是一个父类的对象
// 组合是一种has-a的关系,对象A中有对象B
// 拿stack做例子，stack1继承vector/stack2组合vector
class stack1 : public vector<int>
{
public:
	// ...
};

class stack2
{
public:
	//...
private:
	vector<int> _v;
};

int main()
{
	return 0;
}

// 黑盒测试和白盒测试

// 黑盒测试：不了解底层的实现，从功能角度出发测试
// 白盒测试(难)：了解底层的实现，从代码运行的逻辑角度测试
// 我们需要实现低耦合，高内聚的，我们最好多使用组合少使用继承
